﻿using System;
using System.Windows.Data;
using EzDesk.DesktopClient.Command;
using EzDesk.DesktopClient.UtilityView.ViewModel;
using Microsoft.Practices.Unity;

namespace EzDesk.DesktopClient.ViewModel
{
    using EzDesk.DesktopClient.ViewContract;
    using EzDesk.DesktopClient.Event;
    using System.Collections.Generic;
    using EzDesk.EventAggregation;
    using EzDesk.Generic;
    using EzDesk.DesktopClient.Model;
    using EzDesk.Generic.Collections;
    using System.Linq;
    using EzDesk.DesktopClient.MVVMEnhance;


    public class FeedViewModel : ViewModelWithSingleContainer<IFeedView>
    {
        private bool _displayOnlyMarked;
        public RangeCollection<IFeedItemViewModel> UpdateFeeds { get; set; }

        public DelegateCommand MarkAllReadCommand { get; private set; }
        public DelegateCommand ClearAllCommand { get; private set; }

        public RangeCollection<IFeedItemViewModel> NotificationFeeds { get; set; }

        public int ToHandleCount
        {
            get
            {
                return UpdateFeeds.Count(uf => !uf.IsRead && uf.IsAvailable)
                    + NotificationFeeds.Count(nf => nf.IsAvailable);
            }
        }

        public bool NoFeed
        {
            get
            {
                if(_displayOnlyMarked)
                {
                     return UpdateFeeds.Count(uf => uf.IsMark) == 0 
                         && NotificationFeeds.Count==0;
                }
                return UpdateFeeds.Count == 0
                       && NotificationFeeds.Count == 0;
            }
        }

        public FeedViewModel()
            : base()
        {
            InitMember();
            InitEvent();
        }

        private void InitMember()
        {
            MarkAllReadCommand = new DelegateCommand(OnMarkAllRead);
            ClearAllCommand = new DelegateCommand(OnClearAllCommand);

            this.UpdateFeeds = new RangeCollection<IFeedItemViewModel>(ClientConfigurationManagement.Instance.FeedDisplayCount);
            this.NotificationFeeds = new RangeCollection<IFeedItemViewModel>(10);
        }

        private void OnClearAllCommand()
        {
        }

        private void OnMarkAllRead()
        {
            UpdateFeeds.Foreach(viewModel =>
                                    { viewModel.IsRead = true;
                                    UpdateDataManagement.Instance.UpdateFeedStatusInCache(viewModel.FeedModel);});
        }

        private void InitEvent()
        {
            this.InitGlobalEvent();
            this.InitLocalEvent();
        }

        private void InitGlobalEvent()
        {
            FeedPushEvent.Instance.Subscribe(this.OnDataUpdate, ThreadOption.UIThread);
            ToggleFilterFeedIsMarkEvent.Instance.Subscribe(this.OnFilterFeedIsMark);
        }

        private void InitLocalEvent()
        {
            View.Loaded += View_Loaded;

        }

        void View_Loaded(object sender, System.Windows.RoutedEventArgs e)
        {
            var feedDataArgs = DataManagement.Instance.GetDataFromLocal();
            OnDataUpdate(feedDataArgs);
        }

        private void OnFilterFeedIsMark(bool displayOnlyMarked)
        {
            this._displayOnlyMarked = displayOnlyMarked;
            RefreshView();
        }
        private void RefreshFilter()
        {
            if (_displayOnlyMarked)
                View.SetFilter(feedItemViewModel => feedItemViewModel.IsMark);
            else View.SetFilter(null);
        }

        private void OnDataUpdate(FeedPushArgs args)
        {
            RefreshUpdates(args.UpdateCollection);
            RefreshNotifications(args.NotificationCollection);
            RefreshView();
        }

        private void RefreshView()
        {
            RaisePropertyChanged("ToHandleCount");
            RaisePropertyChanged("NoFeed");
            RefreshFilter();
        }
        private void RefreshUpdates(IEnumerable<Feed> updateCollection)
        {
            //Because some feed type would be changed from update to notification, 
            //so we should remove the related feed from notification view list.
            updateCollection.Foreach(ProcessFeedTypeFromNotificationToUpdate);
            updateCollection.Reverse().Foreach(ProcessPushFeed,UpdateFeeds);
        }

        private void RefreshNotifications(IEnumerable<Feed> notificationCollection)
        {
            notificationCollection.Reverse().Foreach(ProcessPushFeed,NotificationFeeds);
        }


        //TODO:refactory the too long methods
        #region Remove dup feed on UI

        void ViewModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsAvailable")
            {
                var notificationItemViewModel = sender as NotificationItemViewModel;
                if (notificationItemViewModel != null)
                    if (!notificationItemViewModel.IsAvailable)
                    {
                        NotificationFeeds.Remove(notificationItemViewModel);
                        notificationItemViewModel.Dispose();
                    }

                var updateItemViewModel = sender as UpdateItemViewModel;
                if (updateItemViewModel != null)
                    if (!updateItemViewModel.IsAvailable)
                    {
                        UpdateFeeds.Remove(updateItemViewModel);
                        updateItemViewModel.Dispose();
                    }
            }
            RefreshView();
            
        }

        private IFeedItemViewModel GenerateViewModelFromFeed(Feed feed)
        {
            if(feed.Type == FeedType.update.GetEnumName())
            {
                return this.Container.Resolve<UpdateItemViewModel>().SetModel(feed);
            }
            if(feed.Type == FeedType.notification.GetEnumName())
            {
                return this.Container.Resolve<NotificationItemViewModel>().SetModel(feed);
            }

            return null;
        }

        private void ProcessPushFeed(Feed feed,RangeCollection<IFeedItemViewModel> viewModelCollection)
        {
            var itemViewModel = viewModelCollection.FirstOrDefault(uvm => uvm.FeedModel.FeedID == feed.FeedID);
            if (itemViewModel != null)
            {
                if (itemViewModel.FeedModel.UpdateOn != feed.UpdateOn)
                {
                    viewModelCollection.Remove(itemViewModel);
                    var viewModel = GenerateViewModelFromFeed(feed);
                    viewModelCollection.InsertItemAtFirst(viewModel);
                    viewModel.PropertyChanged += ViewModelPropertyChanged;
                }
                if (itemViewModel.FeedModel.LastChangeOn != feed.LastChangeOn)
                {
                    itemViewModel.IsRead = feed.IsRead.Value;
                    itemViewModel.IsMark = feed.IsMark.Value;
                    if (!feed.IsAvailable.Value)
                    {
                        viewModelCollection.Remove(itemViewModel);
                    }
                }
            }
            else
            {
                if (feed.IsAvailable.Value)
                {
                    var viewModel = GenerateViewModelFromFeed(feed);
                    viewModelCollection.InsertItemAtFirst(viewModel);
                    viewModel.PropertyChanged += ViewModelPropertyChanged;
                }
            }
        }

        private void ProcessFeedTypeFromNotificationToUpdate(Feed feed)
        {
            var notificationItemViewModel = NotificationFeeds.FirstOrDefault(uvm => uvm.FeedModel.FeedID == feed.FeedID);
            if(notificationItemViewModel != null)
            {
                NotificationFeeds.Remove(notificationItemViewModel);
            }
        }

        #endregion
    }
}